package net.cassite.daf4j;

import net.cassite.daf4j.util.AutoTx;
import net.cassite.daf4j.util.AutoTxWithReturn;

/**
 * Pure.Data 查询.<br>
 * 将查询封装为对象,通过方法调用和传参进行增删查改
 */
public class Query {
        final DataAccess dataAccess;

        public Query(DataAccess dataAccess) {
                this.dataAccess = dataAccess;
        }

        public <En> From<En> from(En entity) {
                return new From<En>(entity, dataAccess);
        }

        /**
         * 持久化实体
         *
         * @param entities 要持久化的实体
         * @see DataAccess#save(Object[])
         */
        public void save(Object... entities) {
                dataAccess.save(entities);
        }

        /**
         * 根据主键查询实体
         *
         * @param entityClass 实体类
         * @param pkValue     主键值
         * @param <En>        实体类型
         * @return 查询结果, 实体
         * @see DataAccess#find(Class, Object)
         */
        public <En> En find(Class<En> entityClass, Object pkValue) {
                return dataAccess.find(entityClass, pkValue);
        }

        /**
         * 开启事务
         *
         * @return 事务
         */
        public Tx txBegin() {
                dataAccess.txBegin();
                return new Tx(dataAccess);
        }

        /**
         * 自动进行事务,出现异常时将回滚并抛出
         *
         * @param autoTx 执行过程
         */
        public void autoTx(AutoTx autoTx) {
                Tx tx = txBegin();
                try {
                        autoTx.apply(tx);
                        if (tx.isActive())
                                tx.commit();
                } catch (Throwable t) {
                        if (tx.isActive())
                                tx.rollback();
                        throw new RuntimeException(t);
                }
        }

        /**
         * 自动进行事务,有异常时将回滚并抛出
         *
         * @param autoTx 带返回值的进行过程
         * @param <R>    返回类型
         * @return 返回值
         */
        public <R> R autoTx(AutoTxWithReturn<R> autoTx) {
                Tx tx = txBegin();
                try {
                        R res = autoTx.apply(tx);
                        if (tx.isActive())
                                tx.commit();
                        return res;
                } catch (Throwable t) {
                        if (tx.isActive())
                                tx.rollback();
                        throw new RuntimeException(t);
                }
        }

        /**
         * 自动进行事务
         *
         * @param autoTx     带返回值的进行过程
         * @param defaultRes 默认返回值
         * @param <R>        返回类型
         * @return 返回值
         */
        public <R> R autoTx(AutoTxWithReturn<R> autoTx, R defaultRes) {
                Tx tx = txBegin();
                try {
                        R res = autoTx.apply(tx);
                        if (tx.isActive())
                                tx.commit();
                        return res;
                } catch (Throwable t) {
                        if (tx.isActive())
                                tx.rollback();
                        return defaultRes;
                }
        }

        /**
         * 销毁
         */
        public void destroy() {
                dataAccess.destroy();
        }
}
